package com.log.james.controller;

import com.log.james.entity.FwlogFlow;
import com.log.james.entity.R;
import com.log.james.entity.WebFlow;
import com.log.james.service.*;
import com.log.james.utils.IPChangeUtil;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.*;

@Api(tags = "详情接口")
@RestController
@RequestMapping("/detail")
public class DetailsController {

    private SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
    private Logger logger = LoggerFactory.getLogger(this.getClass());
    private IPChangeUtil ipChangeUtil = new IPChangeUtil();

    @Autowired
    private DestIpAnalysisService destIpAnalysisService;
    @Autowired
    private DestPortService destPortService;
    @Autowired
    private SrcIpAnalysisService srcIpAnalysisService;
    @Autowired
    private EventsService eventsService;
    @Autowired
    private FlowService flowService;
    @Autowired
    private FwlogFlowService fwlogFlowService;
    @Autowired
    private WebFlowService webFlowService;
    @Autowired
    private WebLogAttackService webLogAttackService;
    @Autowired
    private WebDDosAnalysisService webDDosAnalysisService;
    /**
     *返回异常事件的详情
     * @param time
     * @param type
     * @return
     */
    @ApiOperation(value = "异常事件详情")
    @PostMapping("/abnormalDetails")
    public R abnormalDetails(String time,String type,String destip,String port) throws ParseException{
        Date startTime = sdf.parse(time);
        logger.info("获取的时间为 " + startTime);
        Map<String,Object> abnormalDetails = new HashMap<>();
        long destIp = ipChangeUtil.ipStrToLong(destip);
        if (type.equals("ipAbnormal")){
            //查询在改时间点是否真的存在异常事件
            Map<String,Object> ipAbnormalMap = destIpAnalysisService.getIpAbnormalDetails(startTime,destIp);
            //判断是否为空
            if (ipAbnormalMap.isEmpty()){
                return R.error("该时间段不存在异常现象");
            }else{
                //将对应的数据封装到Map当中
                abnormalDetails.put("startTime",ipAbnormalMap.get("starttime"));
                abnormalDetails.put("endTime",ipAbnormalMap.get("endtime"));
                abnormalDetails.put("types","IP访问异常");
                abnormalDetails.put("dstIp",strIp(ipAbnormalMap.get("destip")));
                List<Map<String,Integer>> srcIps = new LinkedList<>();
                //将数据存到数组当中
                String[] ips = String.valueOf(ipAbnormalMap.get("srcips")).split(",");
                String[] nums = String.valueOf(ipAbnormalMap.get("counts")).split(",");
                logger.info("ips的长度为 " + ips.length + " nums的长度为 " + nums.length);
                if (ips.length < 20){
                    for (int i = 0 ; i < ips.length ; i++){
                        Map<String,Integer> scrIpNums = new HashMap<>();
                        scrIpNums.put(strIp(ips[i]),Integer.valueOf(nums[i]));
                        srcIps.add(scrIpNums);
                    }
                }else if (ips.length == 20){
                    for (int i = 0 ; i < ips.length ; i++){
                        Map<String,Integer> scrIpNums = new HashMap<>();
                        scrIpNums.put(strIp(ips[i]),Integer.valueOf(nums[i]));
                        srcIps.add(scrIpNums);
                    }
                   Map finalMap = new HashMap();
                    finalMap.put("其他",Integer.valueOf(nums[20]));
                    srcIps.add(finalMap);
                }
                abnormalDetails.put("srcIps",srcIps);
                abnormalDetails.put("count",ipAbnormalMap.get("totalnum"));
                List<Map<String,Object>> features = new LinkedList<>();
                Map<String,Object> feature = new HashMap<>();
                feature.put("每分钟访问的源ip上限",102);
//                features.add(feature);
                //获取访问的ip的数量以及用的时间
                int totalNum = Integer.parseInt(String.valueOf(ipAbnormalMap.get("totalsrcipnum")));
                long useTime = (sdf.parse(String.valueOf(ipAbnormalMap.get("endtime"))).getTime() -
                        sdf.parse(String.valueOf(ipAbnormalMap.get("starttime"))).getTime())/60/1000;
                Map<String,Object> srcipsNum = new HashMap<>();
                logger.info("本次访问的时间为" + useTime);
                feature.put("本次访问的每分钟访问数量",totalNum/useTime);
                features.add(feature);
                abnormalDetails.put("features",features);
                String desc = "从" + ipAbnormalMap.get("starttime") + "到" + ipAbnormalMap.get("endtime")+
                        "ip地址为" + strIp(ipAbnormalMap.get("destip")) + "被" + ipAbnormalMap.get("totalsrcipnum")+
                        "个源ip，访问了" + ipAbnormalMap.get("totalnum") + "次";
                abnormalDetails.put("desc",desc);
                return R.ok().put("data",abnormalDetails);
            }

        } else if (type.equals("portAbnormal")){
            List<Map<String,Object>> destportAbnormal = destPortService.getDestPort(startTime,destIp,Integer.parseInt(port));
            if (destportAbnormal.size() == 0){
                return R.error().put("404","Not Found Data");
            }else{
                abnormalDetails.put("startTime",destportAbnormal.get(0).get("starttime"));
                abnormalDetails.put("endTime",destportAbnormal.get(0).get("endtime"));
                abnormalDetails.put("type","端口访问异常");
                abnormalDetails.put("dstIp",strIp(destportAbnormal.get(0).get("destip")));
                abnormalDetails.put("dstPort",destportAbnormal.get(0).get("destport"));
                List<Map<String,Object>> sources = new LinkedList<>();
                int totalNum = 0;
                for (int i = 0 ; i < destportAbnormal.size() ; i++){
                    Map<String,Object> source = new HashMap<>();
                    source.put("ip",strIp(destportAbnormal.get(i).get("srcip")));
                    source.put("count",destportAbnormal.get(i).get("description"));
                    totalNum += Integer.parseInt(String.valueOf(destportAbnormal.get(i).get("description")));
                    sources.add(source);
                }
                abnormalDetails.put("source",sources);
                abnormalDetails.put("count",totalNum);

                Map<String,Object> feature = new HashMap<>();
                feature.put("理论上每分钟该端口被访问的次数为：",500);
                feature.put("实际上访问的次数为",totalNum/getTime(destportAbnormal.get(0).get("starttime"),
                        destportAbnormal.get(0).get("endtime"))*60000);
                abnormalDetails.put("feature",feature);

                String desc = "从" + destportAbnormal.get(0).get("starttime")+
                        "到" + destportAbnormal.get(0).get("endtime") + "ip地址为" +
                        strIp(destportAbnormal.get(0).get("destip")) + "下的" + destportAbnormal.get(0).get("destport") +
                        "被" + destportAbnormal.size() + "个" + "源ip访问了" + totalNum + "次";
                abnormalDetails.put("desc",desc);

                return R.ok().put("data",abnormalDetails);
            }

        }else if (type.equals("streamAbnormal")){
            //流量异常,获取数据表单当中的数据内容
            List<Map<String,Object>> streamAbnormal = eventsService.getEventsDetails(startTime);
            if (streamAbnormal.size() == 0){
                return R.error().put("404","Data Not Found");
            }else{
                //将这段时间内每分钟的流量值都显示出来
                Date streamStartTime = sdf.parse(String.valueOf(streamAbnormal.get(0).get("starttime")));
                Date streamEndTime = sdf.parse(String.valueOf(streamAbnormal.get(0).get("endtime")));
                abnormalDetails.put("startTime",streamStartTime);
                abnormalDetails.put("endTime",streamEndTime);
                abnormalDetails.put("type","流量异常");
                //记录防火墙的上限流量之和与实时流量之和
                long totalFwCurStream = 0,totalFwMaxStream = 0;
                //分别记录web服务器的预测流量和实时流量之和
                double totalWebCurStream = 0,totalWebMaxStream = 0;
                //获取每分钟的数据量
                List<WebFlow> webFlows = flowService.findFlowByTime(streamStartTime,streamEndTime);
                List<FwlogFlow> fwlogFlows = fwlogFlowService.findFwlogFlowByTime(streamEndTime,streamEndTime);
                List<Map<String,Object>> webStreamData = new LinkedList<>();
                List<Map<String,Object>> firewallStreamData = new LinkedList<>();
                if (webFlows.size() == 0){
                    abnormalDetails.put("webCount",0);
                    abnormalDetails.put("webStreamData","No Data");
                }else{

                    int webLogsNum = webFlowService.getLogsNum(streamStartTime,streamEndTime);
                    abnormalDetails.put("webCount",webLogsNum);
                    for (WebFlow webFlow:webFlows){
                        Map<String,Object> webStream = new HashMap<>();
                        webStream.put("startTime",webFlow.getStarttime());
                        webStream.put("endTime",webFlow.getEndtime());
                        webStream.put("curStream",webFlow.getCurstream());
                        webStream.put("maxStream",webFlow.getUpstream());
                        webStream.put("minStream",webFlow.getDownstream());
                        webStreamData.add(webStream);
                        totalWebCurStream += webFlow.getCurstream();
                        totalWebMaxStream += webFlow.getUpstream();
                    }
                    abnormalDetails.put("webStreamData",webStreamData);
                }
                if (fwlogFlows.size() == 0){
                    abnormalDetails.put("firewallCount",0);
                    abnormalDetails.put("firewallStreamData","No Data");
                }else{
                    for (int i = 0 ; i < fwlogFlows.size() ; i++){
                        Map<String,Object> firewallStream = new HashMap<>();

                        firewallStream.put("startTime",fwlogFlows.get(i).getStarttime());
                        firewallStream.put("endTime",fwlogFlows.get(i).getEndtime());
                        firewallStream.put("curStream",fwlogFlows.get(i).getCurstream());
                        firewallStream.put("maxStream",fwlogFlows.get(i).getUpstream());
                        firewallStream.put("minStream",fwlogFlows.get(i).getDownstream());

                        firewallStreamData.add(firewallStream);
                        totalFwMaxStream += fwlogFlows.get(i).getUpstream();
                        totalFwCurStream += fwlogFlows.get(i).getCurstream();
                    }
                    abnormalDetails.put("firewallCount",totalFwCurStream);
                    abnormalDetails.put("firewallStreamData",firewallStreamData);
                }

                //判断为异常行为的依据
                Map<String,Object> feature = new HashMap<>();
                //预测的上限的平均值，现实中的平均值
                long intervalsTime = (streamStartTime.getTime() - streamEndTime.getTime())/60000;

                feature.put("预测web服务器的每分钟流量上限为",totalWebMaxStream/intervalsTime);
                feature.put("实际上web服务器的该段时间内每分钟流量均值",totalWebCurStream/intervalsTime);
                feature.put("预测的平防火墙均流量上限为",totalFwMaxStream/intervalsTime);
                feature.put("实际上该段时间内防火墙的平均流量为",totalFwCurStream/intervalsTime);
                abnormalDetails.put("desc","流量异常行为");
                return R.ok().put("data",abnormalDetails);
            }


        }else if (type.equals("visitorAbnormal")){
            Map<String,Object> visitAbnormal = srcIpAnalysisService.getSrcIpAbnormal(startTime,destIp);
            if (visitAbnormal.isEmpty()){
                return R.error().put("404","Data Not Found");
            }else{
                abnormalDetails.put("startTime",visitAbnormal.get("starttime"));
                abnormalDetails.put("endTime",visitAbnormal.get("endtime"));
                abnormalDetails.put("type","访客访问异常");
                abnormalDetails.put("srcIp",strIp(visitAbnormal.get("srcip")));
                abnormalDetails.put("srcCity",visitAbnormal.get("srcipaddress"));
                String[] ips = String.valueOf(visitAbnormal.get("destips")).split(",");
                String[] nums = String.valueOf(visitAbnormal.get("counts")).split(",");

                logger.info("ip的数量" + ips.length + " 访问次数的数量" + nums.length);
                List<Map<String,Object>> dstIps = new LinkedList<>();
                for (int i = 0 ; i < ips.length ; i++){
                    Map<String,Object> destips = new HashMap<>();
                    destips.put(strIp(ips[i]),nums[i]);
                    dstIps.add(destips);
                }
                Map<String,Object> othersMap = new HashMap<>();
                othersMap.put("其他",nums[20]);
                dstIps.add(othersMap);

                abnormalDetails.put("dstIps",dstIps);
                abnormalDetails.put("count",visitAbnormal.get("totalnum"));

                Map<String,Object> feature = new HashMap<>();
                int totalNum = Integer.parseInt(String.valueOf(visitAbnormal.get("totaldestipnum")));
                logger.info("总共访问的数量为" + totalNum);
                feature.put("理论上每分钟访问的目的IP数量为" ,109);
                long getTime = getTime(visitAbnormal.get("starttime"),visitAbnormal.get("endtime"));
                logger.info("本次访问的时间为" + getTime);
                logger.info("每分钟访问的数量为" + totalNum*60000/getTime);
                feature.put("实际上每分钟访问的目的IP数量",totalNum*60000/getTime);
                abnormalDetails.put("feature",feature);

                String desc = "从" + visitAbnormal.get("starttime") + "到" + visitAbnormal.get("endtime") +
                        "ip的地址为" + strIp(visitAbnormal.get("srcip")) + "访问了，总共" + visitAbnormal.get("totaldestipnum") +
                        "个目的IP地址，一共" + visitAbnormal.get("totalnum");
                abnormalDetails.put("desc",desc);
                return R.ok().put("data",abnormalDetails);
            }

        } else{
            return R.error("发送数据存在错误");
        }

    }

    /**
     * 返回攻击事件的详情
     * @return
     */
    @ApiOperation(value="攻击详情")
    @PostMapping("/attackDetails")
    public R atackDetails(String time,String type,String ip) throws ParseException{
        Date startTime = sdf.parse(time);
        long IP = ipChangeUtil.ipStrToLong(ip);
        logger.info("前端传递过来的数据为，开始时间：" + startTime + "攻击的类型为：" + type + "ip地址为：" + IP);
        //本次攻击事件的详情
        Map<String,Object> attackDetails = new HashMap<>();
        //判断攻击的类型，若果是根据web日志的url分析出来的攻击
        boolean flag = type.equals("Structs2远程命令执行漏洞") || type.equals("SQL注入攻击") || type.equals("跨站脚本攻击")
                || type.equals("文件包含和路径遍历攻击") || type.equals("webshell") || type.equals("网站敏感文件访问")
                || type.equals("系统命令注入攻击") || type.equals("网络参数修改");
        if (flag){
            Map<String,Object> webLogAttack = webLogAttackService.findAttackDetailsByTimeAndType(startTime,type);
            if (webLogAttack.isEmpty()){
                return R.error("传入的参数有问题");
            }else{
                attackDetails.put("startTime",webLogAttack.get("startTime"));
                attackDetails.put("endTime",webLogAttack.get("endTime"));
                attackDetails.put("type",webLogAttack.get("name"));
                //根据weblogid去查询详细的数据内容
                int weblogid = Integer.parseInt(String.valueOf(webLogAttack.get("weblogid")));
                Map<String,Object> weblogDetail = webLogAttackService.getWeblogDetails(weblogid);
                Map<String,Object> feature = new HashMap<>();
                feature.put("请求URL",weblogDetail.get("url"));
                attackDetails.put("feature",feature);
                attackDetails.put("srcIp",strIp(webLogAttack.get("srcip")));
                attackDetails.put("srcCity",webLogAttack.get("attackaddress"));
                attackDetails.put("desc","URL中发现了" + webLogAttack.get("name") + "攻击的特征字段，经过分析，却认为上述攻类型");
                attackDetails.put("measure",webLogAttack.get("advice"));
                return R.ok().put(String.valueOf(webLogAttack.get("name")),attackDetails);
            }
        }else{
            if(type.equals("端口扫描攻击")){
                Map<String,Object> destportAttack = destPortService.getPortAttackedDetails(startTime,IP);
                if (destportAttack.isEmpty()){
                    return R.error("No Data");
                }else{
                    attackDetails.put("startTime",destportAttack.get("starttime"));
                    attackDetails.put("endTime",destportAttack.get("endtime"));
                    attackDetails.put("type","端口扫描攻击");
                    attackDetails.put("srcIp",strIp(destportAttack.get("srcip")));
                    attackDetails.put("srcCity",destportAttack.get("srcipaddress"));
                    Map<String,Object> feature = new HashMap<>();
                    feature.put("访问的端口数量：",destportAttack.get("totaldestiportnum"));
                    attackDetails.put("feature",feature);
                    attackDetails.put("desc","IP地址" + strIp(destportAttack.get("destip")) +"下的" + destportAttack.get("totaldestiportnum") + "个端口被源IP访问");
                    attackDetails.put("measure","在防火墙配置上添加端口扫描，自动阻断扫描企图");
                    return R.ok().put(type,attackDetails);
                }
            }else if (type.equals("DDos攻击")){
                Map<String,Object> ddosAttackDetails = webDDosAnalysisService.getDDosDetails(startTime);
                attackDetails.put("startTime",ddosAttackDetails.get("starttime"));
                attackDetails.put("endTime",ddosAttackDetails.get("endtime"));
                attackDetails.put("type","DDos攻击");
                Map<String,Object> feature = new HashMap<>();
                feature.put("本次攻击的流量值为",ddosAttackDetails.get("flows"));
                attackDetails.put("measure","扩充带宽，流量清洗，选用高性能设备，过滤掉不必要的服务和端口，限制同时打开的Syn半连接数目，缩短Syn半连接的time out 时间");
                attackDetails.put("desc","本次访问事件在短时间内发送了大量数据包至服务器，经系统判定为恶意攻击服务器");
                return R.ok().put(type,attackDetails);

            }else if (type.equals("ip扫描攻击")){
                Map<String,Object> ipAttackDetails = srcIpAnalysisService.getSrcIpAbnormal(startTime,IP);
                if (ipAttackDetails.isEmpty()){
                    return R.error("No Data");
                }else{
                    attackDetails.put("startTime",ipAttackDetails.get("starttime"));
                    attackDetails.put("endTime",ipAttackDetails.get("endtime"));
                    attackDetails.put("type",type);
                    Map<String,Object> feature = new HashMap<>();
                    feature.put("访问的IP数量",ipAttackDetails.get("totaldestipnum"));
                    feature.put("发起的访问数量",ipAttackDetails.get("totalnum"));
                    attackDetails.put("feature",feature);
                    attackDetails.put("desc","该源IP在短时间内，访问了大量的IP地址，经系统判定为IP扫描攻击");
                    attackDetails.put("measure","在防火墙上过滤掉ICMP应答消息");
                    return R.ok().put(type,attackDetails);
                }
            }else{
                return R.error("系统没有判别出该种类型的攻击");
            }
        }

    }

    private String strIp(Object ip){
        return ipChangeUtil.ipLongToStr(Long.parseLong(String.valueOf(ip)));
    }
    private long getTime(Object st,Object et) throws ParseException{
        return sdf.parse(String.valueOf(et)).getTime() - sdf.parse(String.valueOf(st)).getTime();
    }
}
